﻿// -----------------------------------------------------------------------------
// 园丁,是个很简单的管理系统
//  gitee:https://gitee.com/hgflydream/Gardener 
//  issues:https://gitee.com/hgflydream/Gardener/issues 
// -----------------------------------------------------------------------------

using Gardener.Iot.Services;
using Gardener.Weighbridge.Impl.Core;
using Gardener.Weighbridge.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace Gardener.Weighbridge.Impl.Services
{
    /// <summary>
    /// 地磅控制服务
    /// </summary>
    [ApiDescriptionSettings("Weighbridge", Module = "weighbridge")]
    public class WeighbridgeControlService : IWeighbridgeControlService
    {
        private readonly IDeviceService deviceService;
        private readonly IWeighbridgeConfigService weighbridgeConfigService;
        private readonly ILogger<WeighbridgeControlService> logger;
        /// <summary>
        /// 地磅控制服务
        /// </summary>
        /// <param name="deviceService"></param>
        /// <param name="weighbridgeConfigService"></param>
        /// <param name="logger"></param>
        public WeighbridgeControlService(IDeviceService deviceService, IWeighbridgeConfigService weighbridgeConfigService, ILogger<WeighbridgeControlService> logger)
        {
            this.deviceService = deviceService;
            this.weighbridgeConfigService = weighbridgeConfigService;
            this.logger = logger;
        }
        /// <summary>
        /// 清零
        /// </summary>
        /// <remarks>
        /// 清零
        /// </remarks>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<bool> ZeroOut(CmdInput input)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(input.ChannelIds, b => b.ZeroOut());
            return SendCmd(input.ConfigId, cmds);
        }
        /// <summary>
        /// 读值
        /// </summary>
        /// <remarks>
        /// 读值
        /// </remarks>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<bool> ReadValue(ReadValueCmdInput input)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(input.ChannelIds, b => b.ReadValue(input.Length));
            return SendCmd(input.ConfigId, cmds);
        }

        /// <summary>
        /// 读值
        /// </summary>
        /// <remarks>
        /// 读值
        /// </remarks>
        /// <param name="deviceId"></param>
        /// <param name="channelIds"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        [NonAction]
        public Task<bool> ReadValue(Guid deviceId, int[] channelIds, byte length)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(channelIds, b => b.ReadValue(length));
            return SendCmdByDeviceId(deviceId, cmds);
        }

        /// <summary>
        /// 设置单位
        /// </summary>
        /// <remarks>
        /// 设置单位
        /// </remarks>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<bool> SetUnit(UnitCmdInput input)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(input.ChannelIds, b => b.SetUnit(input.UnitType));
            return SendCmd(input.ConfigId, cmds);
        }

        /// <summary>
        /// 设置小数位
        /// </summary>
        /// <remarks>
        /// 设置小数位
        /// </remarks>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<bool> SetPrecision(PrecisionCmdInput input)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(input.ChannelIds, b => b.SetPrecision(input.PrecisionType));
            return SendCmd(input.ConfigId, cmds);

        }


        /// <summary>
        /// 去皮
        /// </summary>
        /// <remarks>
        /// 设置去皮
        /// </remarks>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<bool> Netweight(NetweightCmdInput input)
        {
            IEnumerable<ModbusCmd>? cmds = GetCmds(input.ChannelIds, b =>
            {
                if (input.NetWeight)
                {
                    return b.Netweight();
                }
                else
                {
                    return b.UnNetweight();
                }
            });
            return SendCmd(input.ConfigId, cmds);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="channelIds"></param>
        /// <param name="handle"></param>
        /// <returns></returns>
        private IEnumerable<ModbusCmd>? GetCmds(int[] channelIds, Func<ModbusCmdBuilder, ModbusCmdBuilder> handle)
        {
            if (channelIds.Length > 0)
            {
                List<ModbusCmd> cmds = new List<ModbusCmd>();
                foreach (var id in channelIds)
                {
                    ModbusCmd c = handle(ModbusCmdBuilder.Create().Address((byte)id)).Build();
                    cmds.Add(c);
                }
                return cmds;
            }
            return null;
        }
        /// <summary>
        /// 向设备发送指令
        /// </summary>
        /// <param name="configId"></param>
        /// <param name="cmds"></param>
        /// <returns></returns>
        private async Task<bool> SendCmd(Guid configId, IEnumerable<ModbusCmd>? cmds)
        {
            var config = await weighbridgeConfigService.Get(configId);
            return await SendCmdByDeviceId(config.DeviceId, cmds);
        }
        /// <summary>
        /// 向设备发送指令
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="cmds"></param>
        /// <returns></returns>
        private async Task<bool> SendCmdByDeviceId(Guid deviceId, IEnumerable<ModbusCmd>? cmds)
        {
            if (cmds == null || !cmds.Any())
            {
                return false;
            }
            for (int i = 0; i < cmds.Count(); i++)
            {
                if (i > 0)
                {
                    //不能发送过快
                    Thread.Sleep(1000);
                }
                var item = cmds.ElementAt(i);
                var result = await deviceService.SendMessage(deviceId, item.GetBody());
                logger.LogInformation("Weighbridge SendCmd deviceId {0} cmd {1} result {2}", deviceId, item.ToString(), result);
            }
            return true;
        }
    }
}
